diff --git a/builtin/clone.c b/builtin/clone.c
index fbfd6568cd..354dadc544 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -844,6 +844,11 @@ static int checkout(int submodule_progress)
 					       "--single-branch" :
 					       "--no-single-branch");
 
+		if (filter_options.choice)
+			strvec_pushf(&args, "--filter=%s",
+				     expand_list_objects_filter_spec(
+					&filter_options));
+
 		err = run_command_v_opt(args.v, RUN_GIT_CMD);
 		strvec_clear(&args);
 	}
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index de5ad73bb8..1ca03ec08b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1658,7 +1658,8 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
 }
 
 static int clone_submodule(const char *path, const char *gitdir, const char *url,
-			   const char *depth, struct string_list *reference, int dissociate,
+			   const char *depth, const char *filter,
+			   struct string_list *reference, int dissociate,
 			   int quiet, int progress, int single_branch)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
@@ -1671,6 +1672,8 @@ static int clone_submodule(const char *path, const char *gitdir, const char *url
 		strvec_push(&cp.args, "--progress");
 	if (depth && *depth)
 		strvec_pushl(&cp.args, "--depth", depth, NULL);
+	if (filter && *filter)
+		strvec_pushl(&cp.args, "--filter", filter, NULL);
 	if (reference->nr) {
 		struct string_list_item *item;
 		for_each_string_list_item(item, reference)
@@ -1803,7 +1806,7 @@ static void prepare_possible_alternates(const char *sm_name,
 
 static int module_clone(int argc, const char **argv, const char *prefix)
 {
-	const char *name = NULL, *url = NULL, *depth = NULL;
+	const char *name = NULL, *url = NULL, *depth = NULL, *filter = NULL;
 	int quiet = 0;
 	int progress = 0;
 	char *p, *path = NULL, *sm_gitdir;
@@ -1834,6 +1837,9 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 		OPT_STRING(0, "depth", &depth,
 			   N_("string"),
 			   N_("depth for shallow clones")),
+		OPT_STRING(0, "filter", &filter,
+			   N_("string"),
+			   N_("object filtering")),
 		OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
 		OPT_BOOL(0, "progress", &progress,
 			   N_("force cloning progress")),
@@ -1847,7 +1853,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 	const char *const git_submodule_helper_usage[] = {
 		N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
 		   "[--reference <repository>] [--name <name>] [--depth <depth>] "
-		   "[--single-branch] "
+		   "[--filter <filter>] [--single-branch] "
 		   "--url <url> --path <path>"),
 		NULL
 	};
@@ -1879,8 +1885,8 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 
 		prepare_possible_alternates(name, &reference);
 
-		if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
-				    quiet, progress, single_branch))
+		if (clone_submodule(path, sm_gitdir, url, depth, filter, &reference,
+				    dissociate, quiet, progress, single_branch))
 			die(_("clone of '%s' into submodule path '%s' failed"),
 			    url, path);
 	} else {
@@ -2002,6 +2008,7 @@ struct submodule_update_clone {
 	int dissociate;
 	unsigned require_init;
 	const char *depth;
+	const char *filter;
 	const char *recursive_prefix;
 	const char *prefix;
 	int single_branch;
@@ -2165,6 +2172,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
 		strvec_push(&child->args, "--dissociate");
 	if (suc->depth)
 		strvec_push(&child->args, suc->depth);
+	if (suc->filter)
+		strvec_push(&child->args, suc->filter);
 	if (suc->single_branch >= 0)
 		strvec_push(&child->args, suc->single_branch ?
 					      "--single-branch" :
@@ -2339,6 +2348,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
 		OPT_STRING(0, "depth", &suc.depth, "<depth>",
 			   N_("Create a shallow clone truncated to the "
 			      "specified number of revisions")),
+		OPT_STRING(0, "filter", &suc.filter, "<filter>",
+			   N_("object filtering")),
 		OPT_INTEGER('j', "jobs", &suc.max_jobs,
 			    N_("parallel jobs")),
 		OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
diff --git a/git-submodule.sh b/git-submodule.sh
index 6fb12585cb..029f7e7f44 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -45,6 +45,7 @@ update=
 prefix=
 custom_name=
 depth=
+filter=
 progress=
 dissociate=
 single_branch=
@@ -132,6 +133,14 @@ cmd_add()
 		--depth=*)
 			depth=$1
 			;;
+		--filter)
+			case "$2" in '') usage ;; esac
+			filter="--filter=$2"
+			shift
+			;;
+		--filter=*)
+			filter=$1
+			;;
 		--)
 			shift
 			break
@@ -268,7 +277,7 @@ or you are unsure what this means choose another name with the '--name' option."
 				eval_gettextln "Reactivating local git directory for submodule '\$sm_name'."
 			fi
 		fi
-		git submodule--helper clone ${GIT_QUIET:+--quiet} ${progress:+"--progress"} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${dissociate:+"--dissociate"} ${depth:+"$depth"} || exit
+		git submodule--helper clone ${GIT_QUIET:+--quiet} ${progress:+"--progress"} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${dissociate:+"--dissociate"} ${depth:+"$depth"} ${filter:+"$filter"} || exit
 		(
 			sanitize_submodule_env
 			cd "$sm_path" &&
@@ -498,6 +507,14 @@ cmd_update()
 		--depth=*)
 			depth=$1
 			;;
+		--filter)
+			case "$2" in '') usage ;; esac
+			filter="--depth=$2"
+			shift
+			;;
+		--filter=*)
+			filter=$1
+			;;
 		-j|--jobs)
 			case "$2" in '') usage ;; esac
 			jobs="--jobs=$2"
@@ -540,6 +557,7 @@ cmd_update()
 		${reference:+"$reference"} \
 		${dissociate:+"--dissociate"} \
 		${depth:+--depth "$depth"} \
+		${filter:+--filter "$filter"} \
 		${require_init:+--require-init} \
 		$single_branch \
 		$recommend_shallow \
