diff --git a/meta-oniro-core/conf/distro/include/oniro-wic.inc b/meta-oniro-core/conf/distro/include/oniro-wic.inc
index cd29d3052a21bebcccc2a05cd3ad82c22f602e6b..094bebab4c424bd4c5fb4fd72fb434abf70b5852 100644
--- a/meta-oniro-core/conf/distro/include/oniro-wic.inc
+++ b/meta-oniro-core/conf/distro/include/oniro-wic.inc
@@ -55,3 +55,9 @@ WIC_ROOTB_PARTITION ?= "part / --source rootfs --use-uuid --fstype=${ROOT_FSTYPE
 WIC_DEVDATA_PARTITION ?= "part --fstype=ext4 --label ${DEVDATA_PARTITION_LABEL} --mkfs-extraopts '-T default' --align 4096 --fixed-size ${DEVDATA_PARTITION_SIZE} ${WIC_DEVDATA_PARTITION_EXTRA_ARGS}"
 WIC_SYSDATA_PARTITION ?= "part --fstype=ext4 --label ${SYSDATA_PARTITION_LABEL} --mkfs-extraopts '-T default' --align 4096 --fixed-size ${SYSDATA_PARTITION_SIZE} ${WIC_SYSDATA_PARTITION_EXTRA_ARGS}"
 WIC_APPDATA_PARTITION ?= "part --fstype=ext4 --label ${APPDATA_PARTITION_LABEL} --mkfs-extraopts '-T default' --align 4096 --fixed-size ${APPDATA_PARTITION_SIZE} ${WIC_APPDATA_PARTITION_EXTRA_ARGS}"
+
+# The construction of the image depends on the files deployed by the
+# oniro-grub-bootconf package, namely the empty grubenv file.
+do_image_wic[depends] += " \
+    oniro-grub-bootconf:do_deploy \
+"
diff --git a/meta-oniro-core/conf/distro/oniro-linux.conf b/meta-oniro-core/conf/distro/oniro-linux.conf
index 710f7ea57089f371cf3e6e478213b7e58656f99b..f91977a9bf093d6e9ad531a53a0620d3b5ad04ae 100644
--- a/meta-oniro-core/conf/distro/oniro-linux.conf
+++ b/meta-oniro-core/conf/distro/oniro-linux.conf
@@ -94,6 +94,13 @@ EFI_PROVIDER = "grub-efi"
 MACHINE_FEATURES:qemux86-64 += "efi"
 MACHINE_FEATURES:qemux86 += "efi"
 
+# Install the grubenv file deployed by oniro-grub-bootconf package into the EFI partition.
+IMAGE_EFI_BOOT_FILES += "grubenv;EFI/BOOT/grubenv"
+
+# Prefer Oniro-specific GRUB configuration file.
+# (note r-provider is used below)
+PREFERRED_RPROVIDER_virtual-grub-bootconf = "oniro-grub-bootconf"
+
 # qemu-generic-arm64 specific requirements
 PREFERRED_VERSION_optee-os:qemu-generic-arm64 = "3.14.0"
 
diff --git a/meta-oniro-core/recipes-bsp/grub/files/grub.cfg b/meta-oniro-core/recipes-bsp/grub/files/grub.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..3d290145cd8f149bffaf3acdd7777980ae85f7d2
--- /dev/null
+++ b/meta-oniro-core/recipes-bsp/grub/files/grub.cfg
@@ -0,0 +1,12 @@
+# SPDX-FileCopyrightText: Huawei Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# NOTE: This file is referenced from x-gpt-efi-disk.wks.in
+# Please be careful when moving it around the tree.
+
+serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
+
+# Boot the "A" slot all the time. This file is a stub.
+linux "(hd0,gpt2)/boot/bzImage" root=/dev/sda2 rauc.slot=A $CMDLINE
+boot
diff --git a/meta-oniro-core/recipes-bsp/grub/files/grubenv b/meta-oniro-core/recipes-bsp/grub/files/grubenv
new file mode 100644
index 0000000000000000000000000000000000000000..f93ccbfff52e5cb00b5ad27c53507ff406e1afcd
--- /dev/null
+++ b/meta-oniro-core/recipes-bsp/grub/files/grubenv
@@ -0,0 +1,2 @@
+# GRUB Environment Block
+#######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
\ No newline at end of file
diff --git a/meta-oniro-core/recipes-bsp/grub/oniro-grub-bootconf.bb b/meta-oniro-core/recipes-bsp/grub/oniro-grub-bootconf.bb
new file mode 100644
index 0000000000000000000000000000000000000000..856c0aa292337142b5708a6b4ec13e272429548e
--- /dev/null
+++ b/meta-oniro-core/recipes-bsp/grub/oniro-grub-bootconf.bb
@@ -0,0 +1,54 @@
+# SPDX-FileCopyrightText: Huawei Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+SUMMARY = "GRUB configuration file specialized for Oniro reference images"
+DESCRIPTION = "This GRUB configuration file has the following features: \
+- Support for A/B immutable system image \
+- Support for try-mode booting compatible with RAUC \
+- Kernel is loaded from the system image \
+"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+SRC_URI = " \
+	file://grub.cfg \
+	file://grubenv \
+"
+
+inherit allarch deploy
+
+RPROVIDES:${PN} += "virtual-grub-bootconf"
+
+# Get definitions of the EFI_ variables.
+require conf/image-uefi.conf
+
+S = "${WORKDIR}"
+
+do_install() {
+	# Install the boot assets into the rootfs. Those can be used to handle boot
+	# asset updates by SysOTA later on. Note that external grub.cfg is
+	# temporary. It must be merged into the grub binary after a period of
+	# testing.
+	install -d ${D}${EFI_FILES_PATH}
+	install -m 644 grub.cfg ${D}${EFI_FILES_PATH}/grub.cfg
+	install -m 644 grubenv ${D}${EFI_FILES_PATH}/grubenv
+}
+
+do_deploy() {
+	# Install the boot assets into DEPLOYDIR. The deploy bbclass
+	# eventually copies those into the boot partition.
+	install -m 644 ${WORKDIR}/grub.cfg ${DEPLOYDIR}
+	# Unlike grub.cfg, nothing installs this file to the boot partition
+	# automatically. It is handled by extending IMAGE_EFI_BOOT_FILES from
+	# conf/distro/oniro-linux.conf.
+	install -m 644 ${WORKDIR}/grubenv ${DEPLOYDIR}
+}
+
+# Cargo-cult from a similar recipe.
+addtask deploy after do_install before do_build
+
+FILES:${PN} = "\
+	${EFI_FILES_PATH}/grub.cfg \
+	${EFI_FILES_PATH}/grubenv \
+"
diff --git a/meta-oniro-core/wic/grub.cfg b/meta-oniro-core/wic/grub.cfg
new file mode 120000
index 0000000000000000000000000000000000000000..b736aef5ecca91d6c08a67cac944e3a43f44a89b
--- /dev/null
+++ b/meta-oniro-core/wic/grub.cfg
@@ -0,0 +1 @@
+../recipes-bsp/grub/files/grub.cfg
\ No newline at end of file
diff --git a/meta-oniro-core/wic/x-gpt-efi-disk.wks.in b/meta-oniro-core/wic/x-gpt-efi-disk.wks.in
index 72e017ae12b9a64f8e86946ab2ac865316c4ecde..7bdb8e9b0d6e1c2cb048fdb43339acbdeb65d68c 100644
--- a/meta-oniro-core/wic/x-gpt-efi-disk.wks.in
+++ b/meta-oniro-core/wic/x-gpt-efi-disk.wks.in
@@ -15,7 +15,15 @@
 # |  |
 # 0  4096KiB
 
-bootloader --ptable gpt --timeout=${WIC_BOOTLOADER_TIMEOUT} --append=" rootfstype=${ROOT_FSTYPE} "
+# The bootloader plugin either generates a file or gets a canned file that
+# needs to be placed in the wic directory. At the same time there's a virtual
+# provider for the GRUB configuration file which installs a file to /boot in
+# the (rootfs). Ideally the file that is installed would be used but this is
+# apparently not supported.
+#
+# We don't want to have a duplicate file but there's no support for relative
+# paths so use a symbolic link instead.
+bootloader --configfile=grub.cfg --ptable gpt --timeout=${WIC_BOOTLOADER_TIMEOUT} --append=" rootfstype=${ROOT_FSTYPE} "
 
 part --source bootimg-efi --sourceparams="loader=${EFI_PROVIDER}" --label ${BOOT_PARTITION_LABEL} --active --align 4096 --offset 4096 --fixed-size ${BOOT_PARTITION_SIZE}
 ${WIC_ROOTA_PARTITION}