diff --git a/bin/bitbake-setup b/bin/bitbake-setup
index 2829e753e145..4aeb78798f86 100755
--- a/bin/bitbake-setup
+++ b/bin/bitbake-setup
@@ -462,8 +462,14 @@ def merge_overrides_into_sources(sources, overrides):
             layers[k] = v
     return layers
 
+def get_configured_sources(config):
+    selected_source_choice = config.get("selected-source-choice")
+    if selected_source_choice is not None:
+        return config["data"]["source-choices"][selected_source_choice]["sources"]
+    return config["data"]["sources"]
+
 def update_build(config, confdir, setupdir, layerdir, d, update_bb_conf="prompt", init_vscode=False, rebase_conflicts_strategy='abort'):
-    layer_config = merge_overrides_into_sources(config["data"]["sources"], config["source-overrides"]["sources"])
+    layer_config = merge_overrides_into_sources(get_configured_sources(config), config["source-overrides"]["sources"])
     sources_fixed_revisions = checkout_layers(layer_config, confdir, layerdir, d, rebase_conflicts_strategy=rebase_conflicts_strategy)
     bitbake_config = config["bitbake-config"]
     thisdir = os.path.dirname(config["path"]) if config["type"] == 'local' else None
@@ -594,6 +600,38 @@ def choose_fragments(possibilities, parameters, non_interactive, skip_selection)
         choices[k] = options_enumerated[option_n][1]["name"]
     return choices
 
+def choose_source_choice(possibilities, selection, parameters, non_interactive):
+    possible_choices = selection if isinstance(selection, list) else [selection]
+    if not possible_choices:
+        raise Exception("Source selection does not contain any source choices.")
+
+    missing_choices = [c for c in possible_choices if c not in possibilities]
+    if missing_choices:
+        raise Exception("Unknown source choice(s): {}".format(missing_choices))
+
+    if len(possible_choices) == 1:
+        only_choice = possible_choices[0]
+        logger.plain("\nSelecting the only available source choice {}".format(only_choice))
+        return only_choice
+
+    cmdline_choices = [c for c in possible_choices if c in parameters]
+    if len(cmdline_choices) > 1:
+        raise Exception("Options specified on command line do not allow a single selection "
+                        f"from source choices {possible_choices}, please remove one or more from {parameters}")
+    if len(cmdline_choices) == 1:
+        return cmdline_choices[0]
+
+    if non_interactive:
+        raise Exception(f"Unable to choose from source choices in non-interactive mode: {possible_choices}")
+
+    logger.plain("")
+    print_configs("Available source choices",
+                  possible_choices,
+                  [possibilities[c]["description"] for c in possible_choices])
+    choice_n = int_input([i[0] for i in list(enumerate(possible_choices, 1))],
+                         "\nPlease select one of the above source choices by its number: ") - 1
+    return possible_choices[choice_n]
+
 def obtain_config(top_dir, registry, args, source_overrides, d):
     if args.config:
         config_id = args.config[0]
@@ -633,8 +671,27 @@ def obtain_config(top_dir, registry, args, source_overrides, d):
         upstream_config = {'type':'registry','registry':registry,'name':config_id,'data':json.load(open(get_registry_config(registry_path,config_id)))}
 
     upstream_config['bitbake-config'] = choose_bitbake_config(upstream_config['data']['bitbake-setup']['configurations'], config_parameters, args.non_interactive)
+
+    source_selection = upstream_config['bitbake-config'].get('source-selection')
+
+    selected_source_choice = None
+    if source_selection is None:
+        if 'sources' not in upstream_config['data']:
+            raise Exception("Configuration template does not define 'sources', and the selected BitBake configuration does not select a source choice.")
+    else:
+        source_choices = upstream_config['data'].get('source-choices')
+        if source_choices is None:
+            raise Exception("BitBake configuration uses 'source-selection' but the configuration template does not define 'source-choices'.")
+        selected_source_choice = choose_source_choice(source_choices, source_selection, config_parameters[1:], args.non_interactive)
+        upstream_config['selected-source-choice'] = selected_source_choice
+
     upstream_config['bitbake-config']['oe-fragment-choices'] = choose_fragments(upstream_config['bitbake-config'].get('oe-fragments-one-of',{}), config_parameters[1:], args.non_interactive, args.skip_selection)
-    upstream_config['non-interactive-cmdline-options'] = [config_id, upstream_config['bitbake-config']['name']] + sorted(upstream_config['bitbake-config']['oe-fragment-choices'].values())
+
+    non_interactive_cmdline_options = [config_id, upstream_config['bitbake-config']['name']]
+    if selected_source_choice is not None:
+        non_interactive_cmdline_options.append(selected_source_choice)
+    non_interactive_cmdline_options += sorted(upstream_config['bitbake-config']['oe-fragment-choices'].values())
+    upstream_config['non-interactive-cmdline-options'] = non_interactive_cmdline_options
     upstream_config['source-overrides'] = source_overrides
     upstream_config['skip-selection'] = args.skip_selection
     return upstream_config
@@ -952,7 +1009,7 @@ def build_status(top_dir, settings, args, d, update=False):
             bb.process.run(["git", "-C", confdir, "restore", "config-upstream.json"])
         return
 
-    layer_config = merge_overrides_into_sources(current_upstream_config["data"]["sources"], current_upstream_config["source-overrides"]["sources"])
+    layer_config = merge_overrides_into_sources(get_configured_sources(current_upstream_config), current_upstream_config["source-overrides"]["sources"])
     if are_layers_changed(layer_config, layerdir, d):
         if update:
             update_build(current_upstream_config, confdir, setupdir, layerdir,
diff --git a/setup-schema/bitbake-setup.schema.json b/setup-schema/bitbake-setup.schema.json
index 99f47f73d0a6..149f1ebab558 100644
--- a/setup-schema/bitbake-setup.schema.json
+++ b/setup-schema/bitbake-setup.schema.json
@@ -15,6 +15,30 @@
         "sources": {
             "$ref": "layers.schema.json#/properties/sources"
         },
+        "source-choices": {
+            "type": "object",
+            "description": "Named choices of sources that configurations can select from with source-selection",
+            "patternProperties": {
+                ".*": {
+                    "type": "object",
+                    "required": [
+                        "description",
+                        "sources"
+                    ],
+                    "properties": {
+                        "description": {
+                            "type": "string",
+                            "description": "Human-readable description of the source choice"
+                        },
+                        "sources": {
+                            "$ref": "layers.schema.json#/properties/sources"
+                        }
+                    },
+                    "additionalProperties": false
+                }
+            },
+            "additionalProperties": false
+        },
         "expires": {
             "type": "string",
             "description": "End of life date for this configuration, in ISO 8601 format (YYYY-MM-DD)"
@@ -73,6 +97,24 @@
                                 "type": "string",
                                 "description": "OE-template configuration"
                             },
+                            "source-selection": {
+                                "description": "Source choice, or list of source choices, that can be used with this configuration",
+                                "oneOf": [
+                                    {
+                                        "type": "string",
+                                        "description": "Named source choice to use for this configuration"
+                                    },
+                                    {
+                                        "type": "array",
+                                        "description": "List of named source choices that can be chosen from for this configuration",
+                                        "minItems": 1,
+                                        "items": {
+                                            "type": "string",
+                                            "description": "Named source choice"
+                                        }
+                                    }
+                                ]
+                            },
                             "oe-fragments": {
                                 "$anchor": "oe-fragments",
                                 "type": "array",
