diff --git a/meson.build b/meson.build
index 556a3f7c42f8..bd19bd836579 100644
--- a/meson.build
+++ b/meson.build
@@ -25,6 +25,9 @@ endif
 
 libcamera_version = libcamera_git_version.split('+')[0]
 
+# This script gererates the .tarball-version file on a 'meson dist' command.
+meson.add_dist_script('utils/run-dist.sh')
+
 # Configure the build environment.
 cc = meson.get_compiler('c')
 cxx = meson.get_compiler('cpp')
diff --git a/utils/gen-version.sh b/utils/gen-version.sh
index da191691a7c5..8759e722ffe1 100755
--- a/utils/gen-version.sh
+++ b/utils/gen-version.sh
@@ -6,6 +6,15 @@
 build_dir="$1"
 src_dir="$2"
 
+# If .tarball-version exists, output the version string from the file and exit.
+# This file is auto-generated on a 'meson dist' command from the run-dist.sh
+# script.
+if [ -f "$src_dir"/.tarball-version ]
+then
+	cat "$src_dir"/.tarball-version
+	exit 0
+fi
+
 # Bail out if the directory isn't under git control
 git rev-parse --git-dir > /dev/null 2>&1 || exit 1
 
diff --git a/utils/run-dist.sh b/utils/run-dist.sh
new file mode 100644
index 000000000000..e89c3733b56c
--- /dev/null
+++ b/utils/run-dist.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# On a meson dist run, generate the version string and store it in a file.
+# This will later be picked up by the utils/gen-version.sh script and used
+# instead of re-generating it. This way, if we are not building in the upstream
+# git source tree, the upstream version information will be preserved.
+
+cd "$MESON_SOURCE_ROOT" || return
+./utils/gen-version.sh > "$MESON_DIST_ROOT"/.tarball-version
