diff --git a/tensorflow/lite/g3doc/guide/android.md b/tensorflow/lite/g3doc/guide/android.md
index a1493090588..72eb07aa34b 100644
--- a/tensorflow/lite/g3doc/guide/android.md
+++ b/tensorflow/lite/g3doc/guide/android.md
@@ -205,8 +205,19 @@ bazel build -c opt --fat_apk_cpu=x86,x86_64,arm64-v8a,armeabi-v7a \
 This will generate an AAR file in `bazel-bin/tensorflow/lite/java/`. Note
 that this builds a "fat" AAR with several different architectures; if you don't
 need all of them, use the subset appropriate for your deployment environment.
-From there, there are several approaches you can take to use the .aar in your
-Android Studio project.
+
+Caution: Following feature is experimental and only available at HEAD. You can
+build smaller AAR files targeting only a set of models as follows:
+
+```sh
+bash tensorflow/lite/tools/build_aar.sh \
+  --input_models=model1,model2 \
+  --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a
+```
+
+Above script will generate the `tensorflow-lite.aar` file and optionally the
+`tensorflow-lite-select-tf-ops.aar` file if one of the models is using
+Tensorflow ops.
 
 ##### Add AAR directly to project
 
diff --git a/tensorflow/lite/tools/BUILD b/tensorflow/lite/tools/BUILD
index 1f57cad7f7a..ad19cd2b519 100644
--- a/tensorflow/lite/tools/BUILD
+++ b/tensorflow/lite/tools/BUILD
@@ -296,6 +296,27 @@ cc_library(
     ],
 )
 
+cc_library(
+    name = "list_flex_ops_no_kernel",
+    srcs = ["list_flex_ops_no_kernel.cc"],
+    hdrs = ["list_flex_ops.h"],
+    deps = [
+        "//tensorflow/lite:framework",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
+tf_cc_binary(
+    name = "list_flex_ops_no_kernel_main",
+    srcs = ["list_flex_ops_main.cc"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":list_flex_ops_no_kernel",
+        "//tensorflow/lite/tools:command_line_flags",
+        "@com_google_absl//absl/strings",
+    ],
+)
+
 tf_cc_test(
     name = "list_flex_ops_test",
     srcs = ["list_flex_ops_test.cc"],
diff --git a/tensorflow/lite/tools/build_aar.sh b/tensorflow/lite/tools/build_aar.sh
new file mode 100755
index 00000000000..6d84d5b35b1
--- /dev/null
+++ b/tensorflow/lite/tools/build_aar.sh
@@ -0,0 +1,214 @@
+#!/bin/bash
+# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+ROOT_DIR="$(cd "${SCRIPT_DIR}/../../../" && pwd)"
+
+function print_usage {
+  echo "Usage:"
+  echo "  $(basename ${BASH_SOURCE}) \\"
+  echo "    --input_models=model1.tflite,model2.tflite \\"
+  echo "    --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a \\"
+  echo "    --tflite_custom_ops_srcs=file1.cc,file2.h \\"
+  echo "    --tflite_custom_ops_deps=dep1,dep2"
+  echo ""
+  echo "Where: "
+  echo "  --input_models: Supported TFLite models. "
+  echo "  --target_archs: Supported arches included in the aar file."
+  echo "  --tflite_custom_ops_srcs: The src files for building additional TFLite custom ops if any."
+  echo "  --tflite_custom_ops_deps: Dependencies for building additional TFLite custom ops if any."
+  echo ""
+  exit 1
+}
+
+function generate_list_field {
+  local name="$1"
+  local list_string="$2"
+  local list=(${list_string//,/ })
+
+  local message+=("$name=[")
+  for item in "${list[@]}"
+  do
+    message+=("\"$item\",")
+  done
+  message+=('],')
+  printf '%s' "${message[@]}"
+}
+
+function print_output {
+  echo "Output can be found here:"
+  for i in "$@"
+  do
+    # Check if the file exist.
+    ls -1a ${ROOT_DIR}/$i
+  done
+}
+
+function generate_tflite_aar {
+  pushd ${TMP_DIR} > /dev/null
+  # Generate the BUILD file.
+  message=(
+    'load("//tensorflow/lite:build_def.bzl", "tflite_custom_android_library")'
+    'load("//tensorflow/lite/java:aar_with_jni.bzl", "aar_with_jni")'
+    ''
+    'tflite_custom_android_library('
+    '    name = "custom_tensorflowlite",'
+  )
+  message+=('    '$(generate_list_field "models" $MODEL_NAMES))
+  message+=('    '$(generate_list_field "srcs" $TFLITE_OPS_SRCS))
+  message+=('    '$(generate_list_field "deps" $FLAG_TFLITE_OPS_DEPS))
+  message+=(
+    ')'
+    ''
+    'aar_with_jni('
+    '    name = "tensorflow-lite",'
+    '    android_library = ":custom_tensorflowlite",'
+    ')'
+    ''
+  )
+  printf '%s\n' "${message[@]}" >> BUILD
+
+  # Build the aar package.
+  popd > /dev/null
+  bazel build -c opt --cxxopt='--std=c++14' \
+        --fat_apk_cpu=${TARGET_ARCHS} \
+        --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
+        //tmp:tensorflow-lite
+
+   OUT_FILES="${OUT_FILES} bazel-bin/tmp/tensorflow-lite.aar"
+}
+
+function generate_flex_aar {
+  pushd ${TMP_DIR}
+  # Generating the BUILD file.
+  message=(
+    'load("//tensorflow/lite/delegates/flex:build_def.bzl", "tflite_flex_android_library")'
+    'load("//tensorflow/lite/java:aar_with_jni.bzl", "aar_with_jni")'
+    ''
+    'tflite_flex_android_library('
+    '    name = "custom_tensorflowlite_flex",'
+    )
+  message+=('    '$(generate_list_field "models" $MODEL_NAMES))
+  message+=(
+    ')'
+    ''
+    'aar_with_jni('
+    '    name = "tensorflow-lite-select-tf-ops",'
+    '    android_library = ":custom_tensorflowlite_flex",'
+    ')'
+  )
+  printf '%s\n' "${message[@]}" >> BUILD
+
+  cp ${ROOT_DIR}/tensorflow/lite/java/AndroidManifest.xml .
+  cp ${ROOT_DIR}/tensorflow/lite/java/proguard.flags .
+  popd
+
+  # Build the aar package.
+  bazel build -c opt --cxxopt='--std=c++14' \
+      --fat_apk_cpu=${TARGET_ARCHS} \
+      --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
+      //tmp:tensorflow-lite-select-tf-ops
+
+  OUT_FILES="${OUT_FILES} bazel-bin/tmp/tensorflow-lite-select-tf-ops.aar"
+}
+
+# Check command line flags.
+TARGET_ARCHS=x86,x86_64,arm64-v8a,armeabi-v7a
+
+if [ "$#" -gt 4 ]; then
+  echo "ERROR: Too many arguments."
+  print_usage
+fi
+
+for i in "$@"
+do
+case $i in
+    --input_models=*)
+      FLAG_MODELS="${i#*=}"
+      shift;;
+    --target_archs=*)
+      TARGET_ARCHS="${i#*=}"
+      shift;;
+    --tflite_custom_ops_srcs=*)
+      FLAG_TFLITE_OPS_SRCS="${i#*=}"
+      shift;;
+    --tflite_custom_ops_deps=*)
+      FLAG_TFLITE_OPS_DEPS="${i#*=}"
+      shift;;
+    *)
+      echo "ERROR: Unrecognized argument: ${i}"
+      print_usage;;
+esac
+done
+
+# Check if users already run configure
+cd $ROOT_DIR
+if [ ! -f "$ROOT_DIR/.tf_configure.bazelrc" ]; then
+  echo "ERROR: Please run ./configure first."
+  exit 1
+else
+  if ! grep -q ANDROID_SDK_HOME "$ROOT_DIR/.tf_configure.bazelrc"; then
+    echo "ERROR: Please run ./configure with Android config."
+    exit 1
+  fi
+fi
+
+# Build the standard aar package of no models provided.
+if [ -z ${FLAG_MODELS} ]; then
+  bazel build -c opt --cxxopt='--std=c++14' \
+    --fat_apk_cpu=${TARGET_ARCHS} \
+    --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
+    //tensorflow/lite/java:tensorflow-lite
+
+  print_output bazel-bin/tensorflow/lite/java/tensorflow-lite.aar
+  exit 0
+fi
+
+# Prepare the tmp directory.
+TMP_DIR="${ROOT_DIR}/tmp/"
+rm -rf ${TMP_DIR} && mkdir -p ${TMP_DIR}
+
+# Copy models to tmp directory.
+MODEL_NAMES=""
+for model in $(echo ${FLAG_MODELS} | sed "s/,/ /g")
+do
+  cp ${model} ${TMP_DIR}
+  MODEL_NAMES="${MODEL_NAMES},$(basename ${model})"
+done
+
+# Copy srcs of additional tflite ops to tmp directory.
+TFLITE_OPS_SRCS=""
+for src_file in $(echo ${FLAG_TFLITE_OPS_SRCS} | sed "s/,/ /g")
+do
+  cp ${src_file} ${TMP_DIR}
+  TFLITE_OPS_SRCS="${TFLITE_OPS_SRCS},$(basename ${src_file})"
+done
+
+# Build the custom aar package.
+generate_tflite_aar
+
+# Build flex aar if one of the models contain flex ops.
+bazel build -c opt --config=monolithic //tensorflow/lite/tools:list_flex_ops_no_kernel_main
+bazel-bin/tensorflow/lite/tools/list_flex_ops_no_kernel_main --graphs=${FLAG_MODELS} > ${TMP_DIR}/ops_list.txt
+if [[ `cat ${TMP_DIR}/ops_list.txt` != "[]" ]]; then
+  generate_flex_aar
+fi
+
+# List the output files.
+rm -rf ${TMP_DIR}
+print_output ${OUT_FILES}
diff --git a/tensorflow/lite/tools/build_aar_with_docker.sh b/tensorflow/lite/tools/build_aar_with_docker.sh
new file mode 100755
index 00000000000..2af4787c35c
--- /dev/null
+++ b/tensorflow/lite/tools/build_aar_with_docker.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+function print_usage {
+  echo "Usage:"
+  echo "  $(basename ${BASH_SOURCE}) \\"
+  echo "    --input_models=model1.tflite,model2.tflite \\"
+  echo "    --target_archs=x86,x86_64,arm64-v8a,armeabi-v7a \\"
+  echo "    --checkpoint=master"
+  echo ""
+  echo "Where: "
+  echo "  --input_models: Supported TFLite models. "
+  echo "  --target_archs: Supported arches included in the aar file."
+  echo "  --checkpoint: Checkpoint of the github repo, could be a branch, a commit or a tag. Default: master"
+  echo ""
+  exit 1
+}
+
+# Check command line flags.
+ARGUMENTS=$@
+TARGET_ARCHS=x86,x86_64,arm64-v8a,armeabi-v7a
+FLAG_CHECKPOINT="master"
+
+if [ "$#" -gt 3 ]; then
+  echo "ERROR: Too many arguments."
+  print_usage
+fi
+
+for i in "$@"
+do
+case $i in
+    --input_models=*)
+      FLAG_MODELS="${i#*=}"
+      shift;;
+    --target_archs=*)
+      TARGET_ARCHS="${i#*=}"
+      shift;;
+    --checkpoint=*)
+      FLAG_CHECKPOINT="${i#*=}"
+      shift;;
+    *)
+      echo "ERROR: Unrecognized argument: ${i}"
+      print_usage;;
+esac
+done
+
+if [ ! -d /tensorflow_src ]; then
+  # Running on host.
+  for model in $(echo ${FLAG_MODELS} | sed "s/,/ /g")
+  do
+    FLAG_DIR="${FLAG_DIR} -v ${model}:${model}"
+  done
+  docker run --rm -it -v $PWD:/tmp -v ${SCRIPT_DIR}:/script_dir ${FLAG_DIR} \
+    --entrypoint /script_dir/build_aar_with_docker.sh tflite-builder \
+    ${ARGUMENTS}
+  exit 0
+else
+  # Running inside docker container, download the SDK first.
+  android update sdk --no-ui -a \
+    --filter tools,platform-tools,android-${ANDROID_API_LEVEL},build-tools-${ANDROID_BUILD_TOOLS_VERSION}
+
+  cd /tensorflow_src
+
+  # Run configure.
+  configs=(
+    '/usr/bin/python3'
+    '/usr/lib/python3/dist-packages'
+    'N'
+    'N'
+    'N'
+    'N'
+    '-march=native -Wno-sign-compare'
+    'y'
+    '/android/sdk'
+  )
+  printf '%s\n' "${configs[@]}" | ./configure
+
+  # Pull the latest code from tensorflow.
+  git pull -a
+  git checkout ${FLAG_CHECKPOINT}
+
+  # Building with bazel.
+  bash /tensorflow_src/tensorflow/lite/tools/build_aar.sh ${ARGUMENTS}
+
+  # Copy the output files from docker container.
+  clear
+  OUT_FILES="/tensorflow_src/bazel-bin/tmp/tensorflow-lite.aar"
+  OUT_FILES="${OUT_FILES} /tensorflow_src/bazel-bin/tmp/tensorflow-lite-select-tf-ops.aar"
+  echo "Output can be found here:"
+  for i in ${OUT_FILES}
+  do
+    if [ -f $i ]; then
+      cp $i /tmp
+      basename $i
+    fi
+  done
+fi
+
diff --git a/tensorflow/lite/tools/list_flex_ops.h b/tensorflow/lite/tools/list_flex_ops.h
index 070da2d9b3d..f9bc7b952df 100644
--- a/tensorflow/lite/tools/list_flex_ops.h
+++ b/tensorflow/lite/tools/list_flex_ops.h
@@ -42,7 +42,7 @@ struct OpKernelCompare {
 using OpKernelSet = std::set<OpKernel, OpKernelCompare>;
 
 // Find flex ops and its kernel classes inside a TFLite model and add them to
-// the map flex_ops. The map stores
+// the map flex_ops.
 void AddFlexOpsFromModel(const tflite::Model* model, OpKernelSet* flex_ops);
 
 // Serialize the list op of to a json string. If flex_ops is empty, return an
diff --git a/tensorflow/lite/tools/list_flex_ops_no_kernel.cc b/tensorflow/lite/tools/list_flex_ops_no_kernel.cc
new file mode 100644
index 00000000000..11a9f39dbfd
--- /dev/null
+++ b/tensorflow/lite/tools/list_flex_ops_no_kernel.cc
@@ -0,0 +1,61 @@
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+#include "tensorflow/lite/tools/list_flex_ops.h"
+
+namespace tflite {
+namespace flex {
+
+std::string OpListToJSONString(const OpKernelSet& flex_ops) {
+  return absl::StrCat("[",
+                      absl::StrJoin(flex_ops, ",\n",
+                                    [](std::string* out, const OpKernel& op) {
+                                      absl::StrAppend(out, "\"", op.op_name,
+                                                      "\"");
+                                    }),
+                      "]");
+}
+
+void AddFlexOpsFromModel(const tflite::Model* model, OpKernelSet* flex_ops) {
+  auto* subgraphs = model->subgraphs();
+  if (!subgraphs) return;
+
+  for (int subgraph_index = 0; subgraph_index < subgraphs->size();
+       ++subgraph_index) {
+    const tflite::SubGraph* subgraph = subgraphs->Get(subgraph_index);
+    auto* operators = subgraph->operators();
+    auto* opcodes = model->operator_codes();
+    if (!operators || !opcodes) continue;
+
+    for (int i = 0; i < operators->size(); ++i) {
+      const tflite::Operator* op = operators->Get(i);
+      const tflite::OperatorCode* opcode = opcodes->Get(op->opcode_index());
+      if (opcode->builtin_code() != tflite::BuiltinOperator_CUSTOM ||
+          !tflite::IsFlexOp(opcode->custom_code()->c_str())) {
+        continue;
+      }
+
+      // Remove the "Flex" prefix from op name.
+      std::string flex_op_name(opcode->custom_code()->c_str());
+      std::string tf_op_name =
+          flex_op_name.substr(strlen(tflite::kFlexCustomCodePrefix));
+
+      flex_ops->insert({tf_op_name, ""});
+    }
+  }
+}
+}  // namespace flex
+}  // namespace tflite