Robert Lewandowski cancelled out an early Christian Pulisic strike to leave the two teams level at the break, but Pierre-Emerick Aubameyang netted 20 minutes from time to hand Dortmund the advantage once again.
Aubameyang and Ousmane Dembele both started for Dortmund, and there was also a spot in the final third for American international Pulisic. French defender Dan-Axel Zagadou and German international Mahmoud Dahoud, meanwhile, made their competitive debuts for BVB.
As for Bayern, Lewandowski, Thomas Muller and Franck Ribery started as the front three in a 4-3-3 formation. There were competitive debuts for Corentin Tolisso and Sebastian Rudy in midfield, while Rafinha and Joshua Kimmich started in the full-back positions.
It was Dortmund that made most of the early running on home soil, with Bayern, who struggled for goals throughout pre-season, finding it difficult to combat the high-press from their opponents.
Lewandowski had Bayern's first clear chance of the match in the 11th minute after a sweeping pass from Rafinha had released the Polish international, but his effort was wide of the post.
Dortmund took the lead less than 60 seconds later, however, when Pulisic robbed Spaniard Javi Martinez of possession before racing into the Bayern box and sliding the ball into the bottom corner of the net.
Peter Bosz's side were ahead for just six minutes though, with Lewandowski levelling the scores from close range in the 18th minute after converting a low cross from Kimmich, who had broken free down the right.
Bayern might have taken the lead just past the 30-minute mark when Muller turned a Ribery cross towards the bottom corner, but Dortmund goalkeeper Roman Burki was on hand to make an excellent reaction save, before Muller headed against the Dortmund post in the 35th minute as Carlo Ancelotti's side continued to dominate.
Tolisso was next to come close for Bayern after beating teenage defender Zagadou in the air, but the midfielder's header was just wide of the post, before Rudy stung the palms of the busy Burki in the latter stages of the first period.
Sebastian Rode came off the Dortmund bench at the interval, with the 26-year-old taking the place of Dahoud, and the alteration appeared to pay dividends as BVB immediately looked more threatening at the start of the second half.
Bayern, on the other hand, struggled to get going after the restart. The Bundesliga champions were also forced into a defensive change just before the hour as new signing Niklas Sule replaced the injured Martinez.
Gonzalo Castro had the opportunity to send Dortmund ahead in the 63rd minute after a wonderful Dembele cross appeared to be landing on the midfielder's head, but he just failed to make contact at the final moment as Bayern's problems continued.
Kingsley Coman came off the Bayern bench in the 67th minute in place of Muller, and the German champions had a brilliant chance to take the lead in the 70th minute when Lewandowski broke into the Dortmund box, but the striker could not find a teammate with his low cross.
Following the Lewandowski opportunity, Dortmund launched an immediate counter-attack, and the German Cup holders took the lead with 71 minutes on the clock as Aubameyang chipped the ball into the far corner of the net after a wonderful through-pass from Dembele.
Renato Sanches, who has been strongly linked with a move away from Bayern this summer, was introduced five minutes from time as Ancelotti looked for some late inspiration on the night.
Dortmund looked to have done enough as the match entered its latter stages, but Bayern levelled the scores in the 88th minute when Kimmich's effort hit Piszczek before landing in the bottom corner as BVB were denied a victory in normal time.
Dembele, Maximilian Philipp, Aubameyang and Castro all scored for Dortmund in the shootout, but Rode missed his team's fourth - allowing Bayern back into the contest - and Bartra's miss at 5-4 Bayern proved decisive as the Bundesliga champions landed the crown for a sixth time.