diff --git a/MAINTAINERS b/MAINTAINERS
index fb2a0a6e3c1f..96ccda9625f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17600,6 +17600,7 @@ ROCKCHIP RK3308 SOUND CARD DRIVER
 M:	Luca Ceresoli <luca.ceresoli@bootlin.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/sound/rockchip,rk3308-audio-graph-card.yaml
+F:	sound/soc/rockchip/rockchip_rk3308_card.c
 
 ROCKCHIP VIDEO DECODER DRIVER
 M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index 42f76bc0fb02..b00dc04f8fd0 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -45,6 +45,20 @@ config SND_SOC_ROCKCHIP_SPDIF
 	  Say Y or M if you want to add support for SPDIF driver for
 	  Rockchip SPDIF transceiver device.
 
+config SND_SOC_ROCKCHIP_RK3308_INTERNAL_CODEC
+	tristate "ASoC sound card based on the internal RK3308 codec"
+	depends on HAVE_CLK && SND_SOC_ROCKCHIP
+	depends on SND_AUDIO_GRAPH_CARD
+	select SND_SOC_ROCKCHIP_I2S_TDM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	help
+	  ASoC sound card driver for the RK3308 internal audio codec.
+
+	  The Rockchip RK3308 SoC has a built-in audio codec that is
+	  connected internally to one out of a selection of the internal
+	  I2S controllers. This driver implements an audio card using these
+	  components.
+
 config SND_SOC_ROCKCHIP_MAX98090
 	tristate "ASoC support for Rockchip boards using a MAX98090 codec"
 	depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && HAVE_CLK
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index 30c57c0d7660..680decae0c02 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -15,6 +15,7 @@ snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
 snd-soc-rk3288-hdmi-analog-objs := rk3288_hdmi_analog.o
 snd-soc-rk3399-gru-sound-objs := rk3399_gru_sound.o
 
+obj-$(CONFIG_SND_SOC_ROCKCHIP_RK3308_INTERNAL_CODEC) += rockchip_rk3308_card.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
 obj-$(CONFIG_SND_SOC_RK3288_HDMI_ANALOG) += snd-soc-rk3288-hdmi-analog.o
diff --git a/sound/soc/rockchip/rockchip_rk3308_card.c b/sound/soc/rockchip/rockchip_rk3308_card.c
new file mode 100644
index 000000000000..3cfc751993fe
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_rk3308_card.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Audio card using the RK3308 internal I2S
+//
+// Allows driving the I2S peripheral with both the RX and TX clocks. This
+// is useful to use the RK3308 internal audio codec.
+//
+// Copyright (c) 2022, Vivax-Metrotech Ltd
+//
+// Based on sound/soc/generic/audio-graph-card.c
+
+#include <linux/module.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/graph_card.h>
+
+static int rk3308_audio_asoc_simple_init_dai(struct snd_soc_dai *dai,
+					     struct asoc_simple_dai *simple_dai)
+{
+	const int nclks = 2; /* The sysclks are clk_id 0 and 1 for the RK3308 driver */
+	int err;
+	int i;
+
+	if (!simple_dai || !simple_dai->sysclk)
+		return 0;
+
+	/* Can be extended to get two different sysclk values via device tree */
+	for (i = 0; i < nclks; i++) {
+		err = snd_soc_dai_set_sysclk(dai, i, simple_dai->sysclk,
+					     simple_dai->clk_direction);
+		if (err && err != -ENOTSUPP)
+			return dev_err_probe(dai->dev, err, "simple-card: set_sysclk error\n");
+	}
+
+	return 0;
+}
+
+static int rk3308_audio_asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
+	struct asoc_simple_dai *dai;
+	int i, ret;
+
+	for_each_prop_dai_codec(props, i, dai) {
+		ret = rk3308_audio_asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai);
+		if (ret < 0)
+			return ret;
+	}
+	for_each_prop_dai_cpu(props, i, dai) {
+		ret = rk3308_audio_asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int rk3308_audio_graph_probe(struct platform_device *pdev)
+{
+	struct asoc_simple_priv *priv;
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	card = simple_priv_to_card(priv);
+	card->driver_name = "rk3308-audio-graph-card";
+	card->probe = asoc_graph_card_probe;
+	priv->init = rk3308_audio_asoc_simple_dai_init;
+
+	return audio_graph_parse_of(priv, dev);
+}
+
+static const struct of_device_id graph_of_rk3308_card_match[] = {
+	{ .compatible = "rockchip,rk3308-audio-graph-card" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, graph_of_rk3308_card_match);
+
+static struct platform_driver rk3308_audio_graph_card = {
+	.driver = {
+		.name = "rk3308-audio-graph-card",
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = graph_of_rk3308_card_match,
+	},
+	.probe = rk3308_audio_graph_probe,
+	.remove = asoc_simple_remove,
+};
+module_platform_driver(rk3308_audio_graph_card);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC Audio Graph Card for Rockchip RK3308");
+MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
