diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
index 6b5c1ac1109eb6e10c27ad7fb88ddd0e8a8fa2f8..1c7156f19c5939867c30d52fdba0ffdcf3583c55 100644
--- a/common/cmd_mmc.c
+++ b/common/cmd_mmc.c
@@ -312,20 +312,14 @@ static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
 		return CMD_RET_FAILURE;
 	}
 	/* Switch to the RPMB partition */
-	original_part = mmc->part_num;
-	if (mmc->part_num != MMC_PART_RPMB) {
-		if (mmc_switch_part(curr_device, MMC_PART_RPMB) != 0)
-			return CMD_RET_FAILURE;
-		mmc->part_num = MMC_PART_RPMB;
-	}
+	original_part = mmc->block_dev.part_num;
+	if (mmc_select_hwpart(curr_device, MMC_PART_RPMB) != 0)
+		return CMD_RET_FAILURE;
 	ret = cp->cmd(cmdtp, flag, argc, argv);
 
 	/* Return to original partition */
-	if (mmc->part_num != original_part) {
-		if (mmc_switch_part(curr_device, original_part) != 0)
-			return CMD_RET_FAILURE;
-		mmc->part_num = original_part;
-	}
+	if (mmc_select_hwpart(curr_device, original_part) != 0)
+		return CMD_RET_FAILURE;
 	return ret;
 }
 #endif
@@ -483,7 +477,7 @@ static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag,
 		printf("mmc%d is current device\n", curr_device);
 	else
 		printf("mmc%d(part %d) is current device\n",
-		       curr_device, mmc->part_num);
+		       curr_device, mmc->block_dev.hwpart);
 
 	return CMD_RET_SUCCESS;
 }
diff --git a/common/env_mmc.c b/common/env_mmc.c
index f182749e8b88931ec18075e95653e8c2d397340b..15aa43d5e1628bcc0ab8508c0b36922565bc06f3 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -69,6 +69,8 @@ __weak uint mmc_get_env_part(struct mmc *mmc)
 	return CONFIG_SYS_MMC_ENV_PART;
 }
 
+static unsigned char env_mmc_orig_hwpart;
+
 static int mmc_set_env_part(struct mmc *mmc)
 {
 	uint part = mmc_get_env_part(mmc);
@@ -79,11 +81,10 @@ static int mmc_set_env_part(struct mmc *mmc)
 	dev = 0;
 #endif
 
-	if (part != mmc->part_num) {
-		ret = mmc_switch_part(dev, part);
-		if (ret)
-			puts("MMC partition switch failed\n");
-	}
+	env_mmc_orig_hwpart = mmc->block_dev.hwpart;
+	ret = mmc_select_hwpart(dev, part);
+	if (ret)
+		puts("MMC partition switch failed\n");
 
 	return ret;
 }
@@ -113,8 +114,7 @@ static void fini_mmc_for_env(struct mmc *mmc)
 #ifdef CONFIG_SPL_BUILD
 	dev = 0;
 #endif
-	if (mmc_get_env_part(mmc) != mmc->part_num)
-		mmc_switch_part(dev, mmc->part_num);
+	mmc_select_hwpart(dev, env_mmc_orig_hwpart);
 #endif
 }
 
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 7ff2a810f303f9b3551934f3661a537730e30d88..395d472e0bd995e7a7e863f786ae0c7fdfa1ca24 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -20,23 +20,6 @@ static unsigned char *dfu_file_buf;
 static long dfu_file_buf_len;
 static long dfu_file_buf_filled;
 
-static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
-{
-	int ret;
-
-	if (part == mmc->part_num)
-		return 0;
-
-	ret = mmc_switch_part(dfu->data.mmc.dev_num, part);
-	if (ret) {
-		error("Cannot switch to partition %d\n", part);
-		return ret;
-	}
-	mmc->part_num = part;
-
-	return 0;
-}
-
 static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
 			u64 offset, void *buf, long *len)
 {
@@ -66,8 +49,9 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
 	}
 
 	if (dfu->data.mmc.hw_partition >= 0) {
-		part_num_bkp = mmc->part_num;
-		ret = mmc_access_part(dfu, mmc, dfu->data.mmc.hw_partition);
+		part_num_bkp = mmc->block_dev.hwpart;
+		ret = mmc_select_hwpart(dfu->data.mmc.dev_num,
+					dfu->data.mmc.hw_partition);
 		if (ret)
 			return ret;
 	}
@@ -91,12 +75,12 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
 	if (n != blk_count) {
 		error("MMC operation failed");
 		if (dfu->data.mmc.hw_partition >= 0)
-			mmc_access_part(dfu, mmc, part_num_bkp);
+			mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
 		return -EIO;
 	}
 
 	if (dfu->data.mmc.hw_partition >= 0) {
-		ret = mmc_access_part(dfu, mmc, part_num_bkp);
+		ret = mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6d88db4bb6dd2fd3a29e7d7d78a5fc458d7ab31d..e6028d503f279ee6617b29e9657d1c8a17e39a85 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -238,6 +238,7 @@ static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
 		       lbaint_t blkcnt, void *dst)
 {
 	int dev_num = block_dev->dev;
+	int err;
 	lbaint_t cur, blocks_todo = blkcnt;
 
 	if (blkcnt == 0)
@@ -247,6 +248,10 @@ static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
 	if (!mmc)
 		return 0;
 
+	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	if (err < 0)
+		return 0;
+
 	if ((start + blkcnt) > mmc->block_dev.lba) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
@@ -581,7 +586,7 @@ int mmc_select_hwpart(int dev_num, int hwpart)
 	if (!mmc)
 		return -ENODEV;
 
-	if (mmc->part_num == hwpart)
+	if (mmc->block_dev.hwpart == hwpart)
 		return 0;
 
 	if (mmc->part_config == MMCPART_NOAVAILABLE) {
@@ -593,8 +598,6 @@ int mmc_select_hwpart(int dev_num, int hwpart)
 	if (ret)
 		return ret;
 
-	mmc->part_num = hwpart;
-
 	return 0;
 }
 
@@ -615,8 +618,10 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
 	 * Set the capacity if the switch succeeded or was intended
 	 * to return to representing the raw device.
 	 */
-	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0)))
+	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
 		ret = mmc_set_capacity(mmc, part_num);
+		mmc->block_dev.hwpart = part_num;
+	}
 
 	return ret;
 }
@@ -1326,7 +1331,7 @@ static int mmc_startup(struct mmc *mmc)
 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
 	}
 
-	err = mmc_set_capacity(mmc, mmc->part_num);
+	err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
 	if (err)
 		return err;
 
@@ -1467,6 +1472,7 @@ static int mmc_startup(struct mmc *mmc)
 
 	/* fill in device description */
 	mmc->block_dev.lun = 0;
+	mmc->block_dev.hwpart = 0;
 	mmc->block_dev.type = 0;
 	mmc->block_dev.blksz = mmc->read_bl_len;
 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
@@ -1626,7 +1632,7 @@ int mmc_start_init(struct mmc *mmc)
 		return err;
 
 	/* The internal partition reset to user partition(0) at every CMD0*/
-	mmc->part_num = 0;
+	mmc->block_dev.hwpart = 0;
 
 	/* Test for SD version 2 */
 	err = mmc_send_if_cond(mmc);
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 6733314942ea4fd4ad67d2b5643878dece2ba343..79b8c4d808fb32c79605dc046417135aed1def9c 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -78,6 +78,10 @@ unsigned long mmc_berase(block_dev_desc_t *block_dev, lbaint_t start,
 	if (!mmc)
 		return -1;
 
+	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	if (err < 0)
+		return -1;
+
 	/*
 	 * We want to see if the requested start or total block count are
 	 * unaligned.  We discard the whole numbers and only care about the
@@ -172,11 +176,16 @@ ulong mmc_bwrite(block_dev_desc_t *block_dev, lbaint_t start, lbaint_t blkcnt,
 {
 	int dev_num = block_dev->dev;
 	lbaint_t cur, blocks_todo = blkcnt;
+	int err;
 
 	struct mmc *mmc = find_mmc_device(dev_num);
 	if (!mmc)
 		return 0;
 
+	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	if (err < 0)
+		return 0;
+
 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
 		return 0;
 
diff --git a/include/mmc.h b/include/mmc.h
index 9254b716b959785c7e17c128b2e78b78aada14c5..465daeb0852a4f1168bb09f2603bea8afec3cd28 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -364,7 +364,6 @@ struct mmc {
 	u8 part_attr;
 	u8 wr_rel_set;
 	char part_config;
-	char part_num;
 	uint tran_speed;
 	uint read_bl_len;
 	uint write_bl_len;
diff --git a/include/part.h b/include/part.h
index 8396ed178eead1f367ccfae281d2d015257b2b24..4d00e220e4c8867c6312044c05a497ec77aaf262 100644
--- a/include/part.h
+++ b/include/part.h
@@ -18,6 +18,7 @@ struct block_dev_desc {
 	unsigned char	part_type;	/* partition type */
 	unsigned char	target;		/* target SCSI ID */
 	unsigned char	lun;		/* target LUN */
+	unsigned char	hwpart;		/* HW partition, e.g. for eMMC */
 	unsigned char	type;		/* device type */
 	unsigned char	removable;	/* removable device */
 #ifdef CONFIG_LBA48