diff --git a/mobile/android/android-components/settings.gradle b/mobile/android/android-components/settings.gradle
index 6ffd2882cfe840fe256266356655d2292db8eafd..75297593e1035cfc5479b234765c3d03afb78d90 100644
--- a/mobile/android/android-components/settings.gradle
+++ b/mobile/android/android-components/settings.gradle
@@ -27,6 +27,7 @@ plugins {
 ext.topsrcdir = rootProject.projectDir.absolutePath.minus("mobile/android/android-components")
 
 apply from: file('../shared-settings.gradle')
+apply from: file('../autopublish-settings.gradle')
 
 buildCache {
     local {
diff --git a/mobile/android/autopublish-settings.gradle b/mobile/android/autopublish-settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..8d233abb12f7c317846acbba3cb9d5dceb782bc9
--- /dev/null
+++ b/mobile/android/autopublish-settings.gradle
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This settings file configures an Android project for substituting a
+// local Application Services and/or Glean.
+//
+// For convenience, this file reads the `autoPublish.*` properties from
+// `$topsrcdir/local.properties`, so that you only need to set them once
+// for all Android projects.
+//
+// You can also set or override these properties on a per-project basis,
+// by setting them in `$topsrcdir/mobile/android/{project}/local.properties`,
+// if you want to only substitute App Services or Glean for a specific project,
+// or to substitute different versions for different projects.
+//
+// This settings file configures the build to automatically publish the
+// contents of your Application Services and Glean checkouts to the
+// Maven local repository. Any dependencies are then substituted to use
+// the locally published versions.
+
+def rootLocalProperties = new File(gradle.mozconfig.topsrcdir, "local.properties").with { localPropertiesFile ->
+    def localProperties = new Properties()
+    if (localPropertiesFile.canRead()) {
+        localPropertiesFile.withInputStream { localProperties.load(it) }
+    }
+    localProperties
+}
+
+[
+    "autoPublish.application-services.dir",
+    "autoPublish.glean.dir",
+].each { key ->
+    def relativeOrAbsolutePath = rootLocalProperties."$key"
+    if (relativeOrAbsolutePath != null) {
+        def autoPublishDir = new File(gradle.mozconfig.topsrcdir).toPath().resolve(relativeOrAbsolutePath)
+        gradle.ext."localProperties.$key" = autoPublishDir.toString()
+    }
+}
+
+gradle.settingsEvaluated {
+    if (gradle.hasProperty("localProperties.autoPublish.application-services.dir")) {
+        // The project that we're configuring now might have overridden
+        // the path from `$topsrcdir/local.properties`, so we need to
+        // resolve it again.
+        def appServicesLocalPath = gradle."localProperties.autoPublish.application-services.dir".with { relativeOrAbsolutePath ->
+            def absolutePath = rootDir.toPath().resolve(relativeOrAbsolutePath).toString()
+            gradle."localProperties.autoPublish.application-services.dir" = absolutePath
+            absolutePath
+        }
+
+        logger.lifecycle("settings.gradle> Enabling automatic publication of application-services from: $appServicesLocalPath")
+        // Windows can't execute .py files directly, so we assume a "manually installed" python,
+        // which comes with a "py" launcher and respects the shebang line to specify the version.
+        def publishAppServicesCmd = [];
+        if (System.properties["os.name"].toLowerCase().contains("windows")) {
+            publishAppServicesCmd << "py";
+        }
+        publishAppServicesCmd << "./automation/publish_to_maven_local_if_modified.py";
+        runCmd(publishAppServicesCmd, appServicesLocalPath, "Published application-services for local development.", false)
+    } else {
+        logger.lifecycle("settings.gradle> Disabled auto-publication of application-services. Enable it by settings 'autoPublish.application-services.dir' in local.properties")
+    }
+
+    if (gradle.hasProperty("localProperties.autoPublish.glean.dir")) {
+        // As above, absolutize the path.
+        def gleanLocalPath = gradle."localProperties.autoPublish.glean.dir".with { relativeOrAbsolutePath ->
+            def absolutePath = rootDir.toPath().resolve(relativeOrAbsolutePath).toString()
+            gradle."localProperties.autoPublish.glean.dir" = absolutePath
+            absolutePath
+        }
+
+        logger.lifecycle("settings.gradle> Enabling automatic publication of Glean from: $gleanLocalPath")
+        // As above, hacks to execute .py files on Windows.
+        def publishGleanCmd = [];
+        if (System.properties["os.name"].toLowerCase().contains("windows")) {
+            publishGleanCmd << "py";
+        }
+        publishGleanCmd << "./build-scripts/publish_to_maven_local_if_modified.py";
+        runCmd(publishGleanCmd, gleanLocalPath, "Published Glean for local development.", false)
+    } else {
+        logger.lifecycle("settings.gradle> Disabled auto-publication of Glean. Enable it by settings 'autoPublish.glean.dir' in local.properties")
+    }
+}
+
+gradle.projectsLoaded { ->
+    gradle.rootProject.allprojects {
+        // Allow local appservices substitution in each project.
+        if (gradle.hasProperty("localProperties.autoPublish.application-services.dir")) {
+            def appServicesSrcDir = gradle."localProperties.autoPublish.application-services.dir"
+            apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
+        }
+
+        // Allow local Glean substitution in each project.
+        if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
+            def gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
+            apply from: "${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
+        }
+    }
+}
+
+def runCmd(cmd, workingDir, successMessage, captureStdout = true) {
+    def proc = cmd.execute(null, new File(workingDir))
+    def standardOutput = captureStdout ? new ByteArrayOutputStream() : System.out
+    proc.consumeProcessOutput(standardOutput, System.err)
+    proc.waitFor()
+
+    if (proc.exitValue() != 0) {
+        throw new GradleException("Process '${cmd}' finished with non-zero exit value ${proc.exitValue()}");
+    } else {
+        logger.lifecycle("settings.gradle> ${successMessage}")
+    }
+    return captureStdout ? standardOutput : null
+}
diff --git a/mobile/android/fenix/settings.gradle b/mobile/android/fenix/settings.gradle
index d18044b859e0623f7aa515779faff947182320e2..5a8eb1841cb90534992c07931972de06db132067 100644
--- a/mobile/android/fenix/settings.gradle
+++ b/mobile/android/fenix/settings.gradle
@@ -33,6 +33,7 @@ plugins {
 ext.topsrcdir = rootProject.projectDir.absolutePath.minus("mobile/android/fenix")
 
 apply from: file('../shared-settings.gradle')
+apply from: file('../autopublish-settings.gradle')
 
 include ':app'
 include ':mozilla-detekt-rules'
diff --git a/mobile/android/focus-android/settings.gradle b/mobile/android/focus-android/settings.gradle
index 52b5321228575bf111d8505af7a9235191415226..9db906b61f8652bd3326cfe0470bf8ae99f7d2a8 100644
--- a/mobile/android/focus-android/settings.gradle
+++ b/mobile/android/focus-android/settings.gradle
@@ -31,6 +31,7 @@ plugins {
 ext.topsrcdir = rootProject.projectDir.absolutePath.minus("mobile/android/focus-android")
 
 apply from: file('../shared-settings.gradle')
+apply from: file('../autopublish-settings.gradle')
 
 include ':app'
 
diff --git a/mobile/android/shared-settings.gradle b/mobile/android/shared-settings.gradle
index 15b9cda955f8b928696ab99d7d93fbb4d7093385..ffdfa28a36cd0860f4d993e18ed4c6497c14d126 100644
--- a/mobile/android/shared-settings.gradle
+++ b/mobile/android/shared-settings.gradle
@@ -168,99 +168,5 @@ gradle.projectsLoaded { ->
                 expand(values)
             }
         }
-
-        // Allow local appservices substitution in each project.
-        if (gradle.hasProperty("localProperties.autoPublish.application-services.dir")) {
-            def appServicesSrcDir = gradle."localProperties.autoPublish.application-services.dir"
-            apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle"
-        }
-
-        // Allow local Glean substitution in each project.
-        if (gradle.hasProperty('localProperties.autoPublish.glean.dir')) {
-            def gleanSrcDir = gradle."localProperties.autoPublish.glean.dir"
-            apply from: "${gleanSrcDir}/build-scripts/substitute-local-glean.gradle"
-        }
-    }
-}
-
-def runCmd(cmd, workingDir, successMessage, captureStdout = true) {
-    def proc = cmd.execute(null, new File(workingDir))
-    def standardOutput = captureStdout ? new ByteArrayOutputStream() : System.out
-    proc.consumeProcessOutput(standardOutput, System.err)
-    proc.waitFor()
-
-    if (proc.exitValue() != 0) {
-        throw new GradleException("Process '${cmd}' finished with non-zero exit value ${proc.exitValue()}");
-    } else {
-        logger.lifecycle("settings.gradle> ${successMessage}")
-    }
-    return captureStdout ? standardOutput : null
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Local Development overrides
-//////////////////////////////////////////////////////////////////////////
-
-def rootLocalProperties = new File(gradle.mozconfig.topsrcdir, "local.properties").with { localPropertiesFile ->
-    def localProperties = new Properties()
-    if (localPropertiesFile.canRead()) {
-        localPropertiesFile.withInputStream { localProperties.load(it) }
-    }
-    localProperties
-}
-
-[
-    "autoPublish.application-services.dir",
-    "autoPublish.glean.dir",
-].each { key ->
-    def relativeOrAbsolutePath = rootLocalProperties."$key"
-    if (relativeOrAbsolutePath != null) {
-        def autoPublishDir = new File(gradle.mozconfig.topsrcdir).toPath().resolve(relativeOrAbsolutePath)
-        gradle.ext."localProperties.$key" = autoPublishDir.toString()
-    }
-}
-
-gradle.settingsEvaluated {
-    if (gradle.hasProperty("localProperties.autoPublish.application-services.dir")) {
-        // The project that we're configuring now might have overridden
-        // the path from `$topsrcdir/local.properties`, so we need to
-        // resolve it again.
-        def appServicesLocalPath = gradle."localProperties.autoPublish.application-services.dir".with { relativeOrAbsolutePath ->
-            def absolutePath = rootDir.toPath().resolve(relativeOrAbsolutePath).toString()
-            gradle."localProperties.autoPublish.application-services.dir" = absolutePath
-            absolutePath
-        }
-
-        logger.lifecycle("settings.gradle> Enabling automatic publication of application-services from: $appServicesLocalPath")
-        // Windows can't execute .py files directly, so we assume a "manually installed" python,
-        // which comes with a "py" launcher and respects the shebang line to specify the version.
-        def publishAppServicesCmd = [];
-        if (System.properties["os.name"].toLowerCase().contains("windows")) {
-            publishAppServicesCmd << "py";
-        }
-        publishAppServicesCmd << "./automation/publish_to_maven_local_if_modified.py";
-        runCmd(publishAppServicesCmd, appServicesLocalPath, "Published application-services for local development.", false)
-    } else {
-        logger.lifecycle("settings.gradle> Disabled auto-publication of application-services. Enable it by settings 'autoPublish.application-services.dir' in local.properties")
-    }
-
-    if (gradle.hasProperty("localProperties.autoPublish.glean.dir")) {
-        // As above, absolutize the path.
-        def gleanLocalPath = gradle."localProperties.autoPublish.glean.dir".with { relativeOrAbsolutePath ->
-            def absolutePath = rootDir.toPath().resolve(relativeOrAbsolutePath).toString()
-            gradle."localProperties.autoPublish.glean.dir" = absolutePath
-            absolutePath
-        }
-
-        logger.lifecycle("settings.gradle> Enabling automatic publication of Glean from: $gleanLocalPath")
-        // As above, hacks to execute .py files on Windows.
-        def publishGleanCmd = [];
-        if (System.properties["os.name"].toLowerCase().contains("windows")) {
-            publishGleanCmd << "py";
-        }
-        publishGleanCmd << "./build-scripts/publish_to_maven_local_if_modified.py";
-        runCmd(publishGleanCmd, gleanLocalPath, "Published Glean for local development.", false)
-    } else {
-        logger.lifecycle("settings.gradle> Disabled auto-publication of Glean. Enable it by settings 'autoPublish.glean.dir' in local.properties")
     }
 }
diff --git a/settings.gradle b/settings.gradle
index 3d474f902610f857756f8623a9ae5a40215b082b..4abb2462fca76f55cf9a47b149bbd3949aa21e9a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,6 +33,7 @@ plugins {
 ext.topsrcdir = rootProject.projectDir.absolutePath
 
 apply from: "${topsrcdir}/mobile/android/shared-settings.gradle"
+apply from: "${topsrcdir}/mobile/android/autopublish-settings.gradle"
 
 // Set the Android SDK location.  This is the *least specific* mechanism, which
 // is unfortunate: we'd prefer to use the *most specific* mechanism.  That is,