diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4c46df0ffb8..01d7025ce4d 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -292,6 +292,15 @@ config MMC_DW_ROCKCHIP
 	  SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well
 	  as removeable SD and micro-SD cards.
 
+config MMC_DW_ROCKCHIP_CLK_HANDOFF
+	bool "Pass MMC clock rate between boot phases via bloblist"
+	depends on MMC_DW_ROCKCHIP && BLOBLIST
+	help
+	  When enabled, the DW MMC source clock rate is saved to the
+	  bloblist after being configured. A later boot phase that lacks
+	  CLK support can read this rate and use it to calculate the
+	  correct clock divider, rather than assuming bypass mode.
+
 config MMC_SDHCI_ADI
 	bool "ADI SD/MMC controller support"
 	depends on ARCH_SC5XX
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 7a72abaa38a..be6436dbe7d 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2013 Google, Inc
  */
 
+#include <bloblist.h>
 #include <clk.h>
 #include <dm.h>
 #include <dt-structs.h>
@@ -50,8 +51,38 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
 
 	ret = clk_set_rate(&priv->clk, freq);
 	if (ret < 0) {
+		/*
+		 * If CLK is not available (e.g. VPL), use the rate saved
+		 * by the previous phase via bloblist. The CRU is still
+		 * configured from that phase, so the DW MMC core can
+		 * calculate the correct clock divider.
+		 */
+		if (!CONFIG_IS_ENABLED(CLK) &&
+		    IS_ENABLED(CONFIG_MMC_DW_ROCKCHIP_CLK_HANDOFF)) {
+			u32 *ratep;
+
+			ratep = bloblist_find(BLOBLISTT_U_BOOT_MMC_CLK,
+					      sizeof(*ratep));
+			if (ratep)
+				return *ratep;
+		}
 		debug("%s: err=%d\n", __func__, ret);
-		return 0;
+		return freq;
+	}
+
+	/* Save the source clock rate for the next phase */
+	if (IS_ENABLED(CONFIG_XPL_BUILD) &&
+	    IS_ENABLED(CONFIG_MMC_DW_ROCKCHIP_CLK_HANDOFF)) {
+		u32 *ratep;
+
+		ratep = bloblist_ensure(BLOBLISTT_U_BOOT_MMC_CLK,
+					sizeof(*ratep));
+		if (ratep) {
+			ulong rate = clk_get_rate(&priv->clk);
+
+			if (!IS_ERR_VALUE(rate))
+				*ratep = rate;
+		}
 	}
 
 	return freq;
