Both teams struggled early in the stifling heat at the San Siro, with Roma’s Edin Dzeko heading wide and Calhanoglu nodding over the bar.
But Stefano Pioli’s Milan dominated after the break with Rebic breaking through after 76 minutes, rifling the ball into the roof of the net at the third attempt after a frantic scramble following a Davide Zappacosta blunder.
Calhanoglu converted a penalty with a minute to go after Chris Smalling fouled Theo Hernandez in the area.
Roma are fifth, six points behind Atalanta who occupy the final Champions League berth and play Udinese later Sunday.
Milan move up to seventh just below the Europa League berths after a second win this week.
Third-placed Inter Milan play Parma later on Sunday looking to keep pace with leaders Juventus and second-placed Lazio.
Juventus beat Lecce 4-0 on Friday, and are four points ahead of Lazio, who came from behind to see off Fiorentina 2-1 on Saturday.