diff --git a/core/Makefile.inc b/core/Makefile.inc
index f80019b6a..263a0e506 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -22,8 +22,12 @@ endif
 
 CORE=core/built-in.a
 
+ifeq ($(CONFIG_PLDM),1)
+include $(SRC)/core/pldm/Makefile.inc
+endif
+
 CFLAGS_SKIP_core/relocate.o = -pg -fstack-protector-all
 CFLAGS_SKIP_core/relocate.o += -fstack-protector -fstack-protector-strong
 CFLAGS_SKIP_core/relocate.o += -fprofile-arcs -ftest-coverage
 
-$(CORE): $(CORE_OBJS:%=core/%)
+$(CORE): $(CORE_OBJS:%=core/%) $(PLDM)
diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc
new file mode 100644
index 000000000..ae45bb8ba
--- /dev/null
+++ b/core/pldm/Makefile.inc
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+# Copyright 2022 IBM Corp
+
+PLDM_DIR ?= core/pldm
+SUBDIRS += $(PLDM_DIR)
+
+CPPFLAGS += -I$(SRC)/pldm/include/
+CPPFLAGS += -I$(SRC)/pldm/include/libpldm/oem/ibm/
+
+PLDM_OBJS = pldm-mctp.o
+
+PLDM = $(PLDM_DIR)/built-in.a
+$(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%)
diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c
new file mode 100644
index 000000000..fb675849d
--- /dev/null
+++ b/core/pldm/pldm-mctp.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+// Copyright 2022 IBM Corp.
+
+#define pr_fmt(fmt) "PLDM: " fmt
+
+#include <cpu.h>
+#include <opal.h>
+#include <stdio.h>
+#include <string.h>
+#include "pldm.h"
+
+/*
+ * PLDM over MCTP (DSP0241)
+ *
+ * First byte of the MCTP message is the message Type = PLDM
+ *    PLDM = 0x01 (000_0001b)
+ *
+ * Next bytes of the MCTP message (MCTP message body) contain the
+ * PLDM message (The base PLDM message fields are defined in DSP0240)
+ */
+
+int pldm_mctp_message_tx(struct pldm_tx_data *tx)
+{
+	tx->mctp_msg_type = MCTP_MSG_TYPE_PLDM;
+
+	return ast_mctp_message_tx(tx->tag_owner, tx->msg_tag,
+				   &tx->mctp_msg_type,
+				   tx->data_size + sizeof(tx->mctp_msg_type));
+}
+
+int pldm_mctp_message_rx(uint8_t eid, bool tag_owner, uint8_t msg_tag,
+			 const uint8_t *buf, int len)
+{
+	struct pldm_rx_data *rx;
+	int rc = 0;
+
+	rx = zalloc(sizeof(struct pldm_rx_data));
+	if (!rx) {
+		prlog(PR_ERR, "failed to allocate rx message\n");
+		return OPAL_NO_MEM;
+	}
+
+	rx->msg = (struct pldm_msg *)buf;
+	rx->source_eid = eid;
+	rx->msg_len = len;
+	rx->tag_owner = tag_owner;
+	rx->msg_tag = msg_tag;
+
+	/* Additional header information */
+	if (unpack_pldm_header(&rx->msg->hdr, &rx->hdrinf)) {
+		prlog(PR_ERR, "%s: unable to decode header\n", __func__);
+		rc = OPAL_EMPTY;
+		goto out;
+	}
+
+out:
+	free(rx);
+	return rc;
+}
+
+int pldm_mctp_init(void)
+{
+	int nbr_elt = 1, rc = OPAL_SUCCESS;
+
+	int (*pldm_config[])(void) = {
+		ast_mctp_init,		/* MCTP Binding */
+	};
+
+	const char *pldm_config_error[] = {
+		"Failed to bind MCTP",
+	};
+
+	prlog(PR_NOTICE, "%s - Getting PLDM data\n", __func__);
+
+	for (int i = 0; i < nbr_elt; i++) {
+		rc = pldm_config[i]();
+		if (rc) {
+			prlog(PR_ERR, "%s\n", pldm_config_error[i]);
+			goto out;
+		}
+	}
+
+out:
+	prlog(PR_NOTICE, "%s - done, rc: %d\n", __func__, rc);
+	return rc;
+}
+
+void pldm_mctp_exit(void)
+{
+	ast_mctp_exit();
+}
diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h
new file mode 100644
index 000000000..bd32cf853
--- /dev/null
+++ b/core/pldm/pldm.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ * Copyright 2022 IBM Corp.
+ */
+
+#ifndef __COREPLDM_H__
+#define __COREPLDM_H__
+
+#include <ast.h>
+#include <base.h>
+#include <pldm.h>
+
+struct pldm_tx_data {
+	/* Contains an message header and payload of an MCTP packet.
+	 * Size of data[]
+	 */
+	size_t data_size;
+
+	/* Holds data related to the routing of an MCTP packet */
+	bool tag_owner;
+	uint8_t msg_tag;
+
+	/* This byte is situated just before the message body */
+	uint8_t mctp_msg_type;
+
+	/* The message payload (e.g. PLDM message) */
+	uint8_t data[1];
+};
+
+struct pldm_rx_data {
+	struct pldm_header_info hdrinf; /* parsed message header */
+
+	struct pldm_msg *msg;
+	int msg_len;
+	int source_eid;
+	bool tag_owner;
+	uint8_t msg_tag;
+};
+
+int pldm_mctp_message_tx(struct pldm_tx_data *tx);
+
+int pldm_mctp_message_rx(uint8_t eid, bool tag_owner, uint8_t msg_tag,
+			 const uint8_t *buf, int len);
+
+#endif /* __COREPLDM_H__ */
diff --git a/hw/ast-bmc/ast-mctp.c b/hw/ast-bmc/ast-mctp.c
index c2efb7b27..00f66abec 100644
--- a/hw/ast-bmc/ast-mctp.c
+++ b/hw/ast-bmc/ast-mctp.c
@@ -12,6 +12,7 @@
 #include <device.h>
 #include <ast.h>
 #include <console.h>
+#include <pldm.h>
 #include <libmctp.h>
 #include <libmctp-cmds.h>
 #include <libmctp-log.h>
@@ -286,6 +287,23 @@ static void message_rx(uint8_t eid, bool tag_owner,
 	prlog(PR_TRACE, "message received: msg type: %x, len %zd"
 			" (eid: %d), rx tag %d owner %d\n",
 			 *msg, len, eid, tag_owner, msg_tag);
+
+	/* The first byte defines the type of MCTP packet payload
+	 * contained in the message data portion of the MCTP message.
+	 * (See DSP0236 for more details about MCTP packet fields).
+	 * For now we only support PLDM over MCTP.
+	 */
+	switch (*msg) {
+	case MCTP_MSG_TYPE_PLDM:
+		/* handle the PLDM message */
+		pldm_mctp_message_rx(eid, tag_owner, msg_tag,
+				     msg + sizeof(uint8_t),
+				     len - sizeof(uint8_t));
+		break;
+	default:
+		prlog(PR_ERR, "%s - not a pldm message type (type: %x)\n",
+			      __func__, *msg);
+	}
 }
 
 /*
diff --git a/include/pldm.h b/include/pldm.h
new file mode 100644
index 000000000..617287fe3
--- /dev/null
+++ b/include/pldm.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ * Copyright 2022 IBM Corp.
+ */
+
+#ifndef __PLDM_H__
+#define __PLDM_H__
+
+/**
+ * Handle PLDM messages received from MCTP
+ */
+int pldm_mctp_message_rx(uint8_t eid, bool tag_owner, uint8_t msg_tag,
+			 const uint8_t *buf, int len);
+
+/**
+ * PLDM over MCTP initialization
+ */
+int pldm_mctp_init(void);
+
+/**
+ * PLDM over MCTP stop
+ */
+void pldm_mctp_exit(void);
+
+#endif /* __PLDM_H__ */
