diff --git a/require-ess/tools/driver.makefile b/require-ess/tools/driver.makefile
index 9c15cd99321e50d76851958cf8e34c69696f192a..767be2199e558cb99cb4faf256d853191745fbeb 100644
--- a/require-ess/tools/driver.makefile
+++ b/require-ess/tools/driver.makefile
@@ -187,9 +187,6 @@ ifndef EPICSVERSION
 ## RUN 1
 # In source directory
 
-export SUBS
-export TMPS
-
 debug::
 	@echo "===================== Pass 1 ====================="
 	@echo "BUILD_EPICS_VERSIONS = ${BUILD_EPICS_VERSIONS}"
@@ -302,18 +299,18 @@ db_internal: $(COMMON_DIR)
 
 -include $(COMMON_DIR)/*.db.d
 
-define SUBS_EXPAND
-vpath $(notdir $2) $(dir $2)
-db_internal: $(COMMON_DIR)/$(notdir $(basename $2).db)
+VPATH += $(dir $(TMPS))
+VPATH += $(dir $(SUBS))
 
-$(COMMON_DIR)/$(notdir $(basename $2).db): $(notdir $2)
-	@printf "Inflating database ... %44s >>> %40s \n" "$$^" "$$@"
-	$(QUIET)$(MSI) -D $$(USR_DBFLAGS) -o $(COMMON_DIR)/$$(notdir $$(basename $2).db) $1 $$^ > $(COMMON_DIR)/$$(notdir $$(basename $2).db).d
-	$(QUIET)$(MSI)    $$(USR_DBFLAGS) -o $(COMMON_DIR)/$$(notdir $$(basename $2).db) $1 $$^
-endef
+$(COMMON_DIR)/%.db: %.template
+	@printf "Inflating database ... %44s >>> %40s \n" "$^" "$@"
+	$(QUIET)$(MSI) -D $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) $^ > $(COMMON_DIR)/$(notdir $(basename $@).db).d
+	$(QUIET)$(MSI)    $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) $^
 
-$(foreach file,$(SUBS),$(eval $(call SUBS_EXPAND,-S,$(file))))
-$(foreach file,$(TMPS),$(eval $(call SUBS_EXPAND,,$(file))))
+$(COMMON_DIR)/%.db: %.substitutions
+	@printf "Inflating database ... %44s >>> %40s \n" "$^" "$@"
+	$(QUIET)$(MSI) -D $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) -S $^ > $(COMMON_DIR)/$(notdir $(basename $@).db).d
+	$(QUIET)$(MSI)    $(USR_DBFLAGS) -o $(COMMON_DIR)/$(notdir $(basename $@).db) -S $^
 
 
 install build debug::
@@ -334,6 +331,12 @@ install build debug:: $(COMMON_DIR)
 	done; \
 	((failed_builds == 0))
 
+# This has to fit under .SECONDEXPANSION in order to catch TMPS and SUBS, which are typically defined
+# _after_ driver.makefile is included.
+.SECONDEXPANSION:
+db_internal: $$(addprefix $(COMMON_DIR)/,$$(notdir $$(patsubst %.template,%.db,$$(TMPS))))
+
+db_internal: $$(addprefix $(COMMON_DIR)/,$$(notdir $$(patsubst %.substitutions,%.db,$$(SUBS))))
 
 else # T_A
 
diff --git a/tests/test_build.py b/tests/test_build.py
index 9f960958eda8dd6caf0a0889aa57ef5ba9af662f..190caa226d7aeb85c33d3594a63452c9cce4537b 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -472,6 +472,42 @@ def test_updated_template_files(wrapper):
     assert db_file.read_text() == "record(ai, updated) {}"
 
 
+def test_expand_db_files(wrapper):
+    wrapper.add_var_to_makefile("TMPS", "templates/a.template")
+    wrapper.add_var_to_makefile("SUBS", "b.substitutions")
+    wrapper.add_var_to_makefile("USR_DBFLAGS", "-I templates")
+
+    template_dir = wrapper.module_dir / "templates"
+    template_dir.mkdir()
+    template_file = template_dir / "a.template"
+    template_file_contents = "record (ai, $(P)) {}"
+    template_file.write_text(template_file_contents)
+
+    substitution_file = wrapper.module_dir / "b.substitutions"
+    substitution_file.write_text(
+        """file "a.template"
+{
+  pattern { P }
+          { "$(PREF)" }
+}
+"""
+    )
+
+    base_version = wrapper.get_env_var("EPICS_VERSION_NUMBER")
+    common_dir = wrapper.module_dir / f"O.{base_version}_Common"
+
+    rc, *_ = wrapper.run_make("db_internal")
+    assert rc == 0
+
+    expanded_template_file = common_dir / "a.db"
+    assert expanded_template_file.read_text() == template_file_contents
+
+    expanded_substitution_file = common_dir / "b.db"
+    assert expanded_substitution_file.read_text() == template_file_contents.replace(
+        "$(P)", "$(PREF)"
+    )
+
+
 @pytest.mark.parametrize(
     "installed_archs, param, expected",
     [